<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>三维向量及控制物体前进</title>
<style>
html,body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
}
</style>
</head>

<body>
<script type="importmap">
{
    "imports": {
        "three": "../js/threejs/three.module.js",
        "three/addons/": "../js/threejs/jsm/"
    }
}
</script>
<script type="module">
    import * as THREE from 'three';
    import { TrackballControls } from 'three/addons/controls/TrackballControls.js';
    import { DragControls } from 'three/addons/controls/DragControls.js';
    import { TransformControls } from 'three/addons/controls/TransformControls.js';
    import { OrbitControls } from 'three/addons/controls/OrbitControls.js';//倒入轨道控制器
    import {RenderPass} from 'three/addons/postprocessing/RenderPass.js';
    import {OutlinePass} from 'three/addons/postprocessing/OutlinePass.js';
    import {EffectComposer} from 'three/addons/postprocessing/EffectComposer.js';

    import {GUI} from 'three/addons/libs/lil-gui.module.min.js';// 导入lil-gui
   
    import * as ThreeComm from '../js/three-comm.js';
    import threeUtil from '../js/three-cube.js';

    import * as MessEditor from '../js/three-edit.js';
    
    let pSceneMessEditor;
    
    
    // 创建场景
    const scene = new THREE.Scene();
    // 创建相机
    const camera = new THREE.PerspectiveCamera( // 透视相机
        75, // 视角 角度数
        window.innerWidth / window.innerHeight, // 宽高比 占据屏幕
        0.1, // 近平面（相机最近能看到物体）
        1000, // 远平面（相机最远能看到物体）
    );
    camera.position.set(0, 10, 30);
    // 创建渲染器
    const renderer = new THREE.WebGLRenderer({
        antialias: true, // 抗锯齿
    });

    // 设置渲染器宽高
    renderer.setSize(window.innerWidth, window.innerHeight);
    // renderer（渲染器）的dom元素添加到我们的HTML文档中
    document.body.appendChild(renderer.domElement);

    // 地面
    // const plane = new THREE.Mesh(
    //     new THREE.PlaneGeometry(120, 100),
    //     new THREE.MeshStandardMaterial({
    //         color: 0x817936,
    //     })
    // );
    // plane.rotation.x = -Math.PI / 2;
    // // 添加到场景中
    // scene.add(plane);

    // 添加灯光
    const ambientLight = new THREE.AmbientLight(0x404040, 100);
    scene.add(ambientLight);

    // 创建球体
    const sphereGeometry = new THREE.SphereGeometry(2, 32, 32);
    const sphereMaterial = new THREE.MeshStandardMaterial({
        color: 0xfff000,
    })
    const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
    sphere.position.set(0, 2, 0);
    sphere.userData = {type:'sphere'}
    scene.add(sphere);

    //创建一个立方体几何对象Geometry
    var geometry = new THREE.BoxGeometry(6, 6, 6);
    //给几何体创建材质，这里是改为蓝色，材质对象Material
    var material = new THREE.MeshLambertMaterial({color: 0xFF00ff});
    //网格模型对象Mesh
    var mesh = new THREE.Mesh(geometry, material);
    //网格模型添加到场景中，每个模型最终都要添加到场景中才会被渲染
    mesh.name = 'box'
    mesh.position.x = 0;
    mesh.position.y = 0;
    mesh.position.z = 0;
    mesh.userData = {type:'cub'}

    scene.add(mesh);

    
    

    var optCubes = [
      { "data": { "id": "101", "type": "LQ", "name": "L03", "color": "#5F9EA0" ,cg:5}, "points": [{ "x": -1, "y": 1 }, { "x": 3, "y": 4 }, { "x": 1, "y": 6 }, { "x": -3, "y": 3 }] },
    ];

    var hCubes = []
    var optCube = optCubes[0];  
    var iCubeNum = optCubes.length
    var iCubeIdx
    
    for (iCubeIdx = 0; iCubeIdx < iCubeNum; iCubeIdx++) {
      optCube = optCubes[iCubeIdx];
      threeUtil.addCube(optCube, hCubes, camera,scene)
    }




    var faceArraws = null;
    var arrow //= createArraw(mesh,0)
    // arrow = createArraw(mesh,0,faceArraws)
    // arrow = createArraw(mesh,1,faceArraws)
    // arrow = createArraw(mesh,2,faceArraws)
    // arrow = createArraw(mesh,3,faceArraws)
    // arrow = createArraw(mesh,4,faceArraws)
    // arrow = createArraw(mesh,5,faceArraws)

    //var hMess = ThreeComm.findParentMess(arrow,'');
    //console.log('findParentMess arrow.parent',hMess);

    // arrow = createArraw(hCubes[0],0,faceArraws)
    // arrow = createArraw(hCubes[0],1,faceArraws)
    // arrow = createArraw(hCubes[0],2,faceArraws)
    // arrow = createArraw(hCubes[0],3,faceArraws)
    // arrow = createArraw(hCubes[0],4,faceArraws)
    // arrow = createArraw(hCubes[0],5,faceArraws)

    const axesHelper = new THREE.AxesHelper(25);
    scene.add(axesHelper);
    // 键位
    const keyEvent = {
        W: false,
    };

    // 事件
    window.addEventListener("keydown", (event) => {
        const keyCode = event.key.toUpperCase();
        console.log(keyCode);
        if (keyEvent.hasOwnProperty(keyCode)) {
            keyEvent[keyCode] = true;
        }
    });
    window.addEventListener("keyup", (event) => {
        const keyCode = event.key.toUpperCase();
        if (keyEvent.hasOwnProperty(keyCode)) {
            keyEvent[keyCode] = false;
        }
    });
    const velocity = new THREE.Vector3(0,0,-0.033333);

    var dragControls = new DragControls(scene.children,camera, renderer.domElement);

      
    // 添加鼠标控制
    var orbitControls = new OrbitControls(camera, renderer.domElement);
    orbitControls.enableDamping = true; // 使得相机移动更加平滑
    orbitControls.dampingFactor = 0.05; // 阻尼效果

    var dragMess   = null;
    var dragMarker = null;
    //在场景中添加拖拽辅助对象，默认对所有课拖拽模型生效
    // 鼠标略过事件
    dragControls.addEventListener('hoveron', function (event) {
      // 让变换控件对象和选中的对象绑定
      //transformControls.attach(event.object);
    });
    // 开始拖拽
    dragControls.addEventListener('drag', function (event) {
      orbitControls.enabled = false;
      if(ThreeComm.isEmpty(event) || ThreeComm.isEmpty(dragMess)){
        return;
      }
      var hDragObj    = event.object;
      var bIsMarker   = MessEditor.isDragMarker(hDragObj);
      if(!bIsMarker){
        return;
      }
      var curPoint        = hDragObj.position;//;
      var projectionPoint = MessEditor.getRaycasterProjectionPoint(hDragObj,curPoint);
      if(!ThreeComm.isEmpty(projectionPoint)){
        hDragObj.position.x = projectionPoint.x;
        hDragObj.position.y = projectionPoint.y;
        hDragObj.position.z = projectionPoint.z;
      }
      var scale = MessEditor.getDragScaleByMarker(scene,hDragObj);
      console.log('drag event=',event,'scale=',scale,'projectionPoint=',projectionPoint);
      if(scale==0){
        return;
      }
      //dragMess.scale();
      
    });
    // 开始拖拽
    dragControls.addEventListener('dragstart', function (event) {
      orbitControls.enabled = false;
      if(ThreeComm.isEmpty(event)){
        return;
      }
      var hDragObj    = event.object;
      var bIsMarker   = MessEditor.isDragMarker(hDragObj);
      var bIsDragMessr= MessEditor.isDragMess(hDragObj);
      if(bIsMarker){
        dragMarker = hDragObj;
        return ;
      }else if(bIsDragMessr){
        MessEditor.clearDragMarkers(scene,dragMess);
        dragMess = hDragObj;
        MessEditor.createDragMarkers(scene,dragMess);
      }
    });
    // 拖拽结束
    dragControls.addEventListener('dragend', function (event) {
      //renderer.render( scene, camera );
      //物体拖拽完毕，将轨迹控制器开启
      orbitControls.enabled = true; 
    });

    //pSceneMessEditor = new PMessEditor(scene,camera,renderer,dragControls);
    

    
    function removeArraw(faceArraws){
        if(!ThreeComm.isArray(faceArraws)){
            return ;
        }
        //查找箭头的父模型
        var hParent = null;
        var iSize = faceArraws.length;
        var arrow = null;
        for(var i=0;i<iSize;i++){
            arrow = faceArraws[i];
            if(ThreeComm.isEmpty(arrow)){
                continue;
            }
            hParent = ThreeComm.findParentMess(arrow);
            if(!ThreeComm.isEmpty(hParent)){
                break;
            }
        }
        if(ThreeComm.isEmpty(hParent) || ThreeComm.isEmpty(hParent.children)){
            return;
        }
        var hChild;
        var messType;
        iSize = hParent.children.length;
        for(var i=iSize-1;i>=0;i--){
            hChild = hParent.children[i];
            messType= ThreeComm.getMessType(hChild);
            if(messType=='ArrowHelper'){
                hParent.remove(hChild);
            }
        }
    }

    //创建法向量的箭头 https://blog.csdn.net/u014291990/article/details/135322526
    function createArraw(hMess,faceIdx,faceArraws){
      if(ThreeComm.isEmpty(hMess)){
        console.log('hMess is null');
        return null;
      }
      if(!ThreeComm.isNum(faceIdx)){
        console.log('faceIdx is not num');
        return null;
      }
      var points     = ThreeComm.getMessPoints(hMess);
      var facePoints = ThreeComm.getMessFacePoints(hMess,faceIdx,points);
      var centerPoint= ThreeComm.getCenterPoint(facePoints);
      //已知三角形三个顶点的坐标，计算三角形法线方向
      var idx1 = 0;
      var idx2 = 1;
      var idx3 = 2;

      if(faceIdx==0){
        idx1 = 2;
        idx2 = 1;
        idx3 = 0;
      }else if(faceIdx==1){
        idx1 = 0;
        idx2 = 1;
        idx3 = 2;
      }else if(faceIdx==2){
        idx1 = 0;
        idx2 = 1;
        idx3 = 2;
      }else if(faceIdx==3){
        idx1 = 0;
        idx2 = 1;
        idx3 = 3;
      }else if(faceIdx==4){
        idx1 = 3;
        idx2 = 1;
        idx3 = 0;
      }

      var p1 = ThreeComm.pointToVector3(facePoints[idx1]);
      var p2 = ThreeComm.pointToVector3(facePoints[idx2]);
      var p3 = ThreeComm.pointToVector3(facePoints[idx3]);

      // 三个顶点构建两个向量，按照三角形顶点的顺序，构建1指向2的向量，2指向3的向量
      var a = p2.clone().sub(p1);
      var b = p3.clone().sub(p2);
      var c = a.clone().cross(b);
      c.normalize();//向量c归一化表示三角形法线方向
      
      if(c.x ==0 && c.y==0 && c.z==0){
        //return null;
      }
      
      // 可视化向量a和b叉乘结果：向量c
      var arrow = null;
      if(ThreeComm.isArray(faceArraws)){
        var iSize = faceArraws.length;
        if(faceIdx>=0 && faceIdx<iSize){
            arrow = faceArraws[faceIdx];
        }
      }
      if(null==arrow){
        arrow = new THREE.ArrowHelper(c,centerPoint,  8, 0xfff000);
        if(ThreeComm.isArray(faceArraws)){
            while(faceArraws.length<=faceIdx){
                faceArraws.push(null);
            }
            faceArraws[faceIdx] = arrow;
        }
      }else{
        arrow.copy(centerPoint)
        arrow.setDirection(c);
      }
      arrow.userData = {type:'drag',faceIdx:faceIdx}
      //console.log('faceIdx=',faceIdx,'points=',points,'facePoints=',facePoints,'centerPoint=',centerPoint,'c=',c,'arrow=',arrow);
      hMess.add(arrow);
      return arrow;
    }
    
    // 渲染循环动画
    function animate() {
        // 在这里我们创建了一个使渲染器能够在每次屏幕刷新时对场景进行绘制的循环（在大多数屏幕上，刷新率一般是60次/秒）
        requestAnimationFrame(animate);
        if (keyEvent.W) {
            sphere.position.add(velocity);
        }
        // 更新控制器。如果没在动画里加上，那必须在摄像机的变换发生任何手动改变后调用
        //control.update();
        renderer.render(scene, camera);
    };

    // 执行动画
    animate();
</script>
</body>
</html>